using System.Linq;
using FireStarter.Base;
using FireStarter.Base.BusinessObjectMerger;
using FireStarterModeller.BO;
using FireStarterModeller.Logic.MergeBusinessObjects;
using FireStarterModeller.Test.BO;
using Habanero.Testability;
using NUnit.Framework;
using TestabilityExtensions = Habanero.Testability.TestabilityExtensions;

namespace FireStarterModeller.Test.Logic.MergeBusinessObjects
{
    [TestFixture]
    public class TestMergeUIGridInfo
    {
        [TestFixtureSetUp]
        public virtual void TestFixtureSetup()
        {
            TestUtilsLogic.SetupFixture();
        }
        [SetUp]
        public virtual void SetupTest()
        {
            TestUtilsLogic.SetupTest();
        }

        [Test]
        public void Test_MergeUIGridInfo_WhenNewColumns_ShouldMergeUIColumns()
        {
            //---------------Set up test pack-------------------
            var uiGridColumnInfoMerger = MergeableBORegistry.Instance.Resolve<UIGridInfo>();
            var fromUIGridInfo = TestUtilsUIGridInfo.GetFactory()
                .WithMany(columnLayout => columnLayout.UIColumns)
                .WithOutSingleRelationships()
                .CreateValidBusinessObject();
            var uiGridColumnInfos = fromUIGridInfo.UIColumns;
            SetOrdinalPos(uiGridColumnInfos[0]);
            SetOrdinalPos(uiGridColumnInfos[1]);
            SetOrdinalPos(uiGridColumnInfos[2]);
            var toUIGridInfo = new UIGridInfo();
            //---------------Assert Precondition----------------
            Assert.Greater(fromUIGridInfo.UIColumns.Count, 2);
            Assert.AreEqual(0, toUIGridInfo.UIColumns.Count);
            //---------------Execute Test ----------------------
            uiGridColumnInfoMerger.MergeBOFrom(fromUIGridInfo, toUIGridInfo);
            //---------------Test Result -----------------------
            Assert.AreEqual(fromUIGridInfo.UIColumns.Count, toUIGridInfo.UIColumns.Count);
        }

        [Test]
        public void Test_MergeUIGridInfo_WhenTwoUpdatedColumns_ShouldUpdateColumns()
        {
            //---------------Set up test pack-------------------
            var uiGridColumnInfoMerger = MergeableBORegistry.Instance.Resolve<UIGridInfo>();
            var fromUIGridInfo = TestUtilsUIGridInfo.GetFactory()
                .WithTwo(columnLayout => columnLayout.UIColumns)
                .WithOutSingleRelationships()
                .CreateValidBusinessObject();
            var uiGridColumnInfos = fromUIGridInfo.UIColumns;
            var fromUIGridColumnInfo = uiGridColumnInfos[0];
            SetOrdinalPos(fromUIGridColumnInfo);
            var fromUIGridColumnInfo2 = uiGridColumnInfos[1];
            SetOrdinalPos(fromUIGridColumnInfo2);

            var toUIGridInfo = new UIGridInfo ();
            UIGridColumnInfo expectedToUIGridColumnInfo = AddCopiedUIGridColumnInfo(toUIGridInfo, fromUIGridColumnInfo);
            UIGridColumnInfo expectedToUIGridColumnInfo2 = AddCopiedUIGridColumnInfo(toUIGridInfo, fromUIGridColumnInfo2);

            //---------------Assert Precondition----------------
            Assert.AreEqual(2, fromUIGridInfo.UIColumns.Count);
            Assert.AreEqual(fromUIGridColumnInfo.PropertyName, expectedToUIGridColumnInfo.PropertyName);
            //MergeUIGridColumnInfo Specialises the matchBusinessObject            Assert.AreEqual(fromUIGridColumnInfo.ToString(), expectedToUIGridColumnInfo.ToString());
            Assert.AreNotEqual(fromUIGridColumnInfo.OrdinalPosition, expectedToUIGridColumnInfo.OrdinalPosition);
            Assert.AreEqual(fromUIGridColumnInfo2.PropertyName, expectedToUIGridColumnInfo2.PropertyName);
            Assert.AreNotEqual(fromUIGridColumnInfo2.OrdinalPosition, expectedToUIGridColumnInfo2.OrdinalPosition);
            //MergeUIGridColumnInfo Specialises the matchBusinessObject            Assert.AreEqual(fromUIGridColumnInfo2.ToString(), expectedToUIGridColumnInfo2.ToString());
            //---------------Execute Test ----------------------
            uiGridColumnInfoMerger.MergeBOFrom(fromUIGridInfo, toUIGridInfo);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toUIGridInfo);
            Assert.AreEqual(2, toUIGridInfo.UIColumns.Count);
            var toUIGridColumnInfo = toUIGridInfo.UIColumns.First();
            Assert.AreEqual(fromUIGridColumnInfo.PropertyName, toUIGridColumnInfo.PropertyName);
            Assert.AreEqual(fromUIGridColumnInfo.OrdinalPosition, toUIGridColumnInfo.OrdinalPosition);
            var toUIGridColumnInfo2 = toUIGridInfo.UIColumns.Last();
            Assert.AreEqual(fromUIGridColumnInfo2.PropertyName, toUIGridColumnInfo2.PropertyName);
            Assert.AreEqual(fromUIGridColumnInfo2.OrdinalPosition, toUIGridColumnInfo2.OrdinalPosition);
        }

        private static void SetOrdinalPos(UIGridColumnInfo uiGridColumnInfo)
        {
            uiGridColumnInfo.OrdinalPosition = GetValidOrdinalPos(uiGridColumnInfo);
        }

        private static int? GetValidOrdinalPos(UIGridColumnInfo uiGridColumnInfo)
        {
            return GetFactory().GetValidPropValue(uiGridColumnInfo, gridColumn => gridColumn.OrdinalPosition);
        }

        private static BOTestFactory<UIGridColumnInfo> GetFactory()
        {
            return TestUtilsUIGridColumnInfo.GetFactory();
        }
        [Test]
        public void Test_MergeUIGridInfo_WhenOneRemovedUIGrid_ShouldUpdateFieldStatusToDelete()
        {
            //---------------Set up test pack-------------------
            var uiGridColumnInfoMerger = MergeableBORegistry.Instance.Resolve<UIGridInfo>();
            var fromUIGridInfo = new UIGridInfo();
            var fromUIGridColumnInfo = CreateUIGridColumnInfo(fromUIGridInfo);
            var fromUIGridColumnInfo2 = CreateUIGridColumnInfo(fromUIGridInfo);
            var toUIGridInfo = new UIGridInfo();
            UIGridColumnInfo expectedToUIGridColumnInfo = AddCopiedUIGridColumnInfo(toUIGridInfo, fromUIGridColumnInfo);
            UIGridColumnInfo expectedToUIGridColumnInfo2 = AddCopiedUIGridColumnInfo(toUIGridInfo, fromUIGridColumnInfo2);
            fromUIGridInfo.UIColumns.Remove(fromUIGridColumnInfo2);
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, fromUIGridInfo.UIColumns.Count);
            Assert.AreEqual(2, toUIGridInfo.UIColumns.Count);
            Assert.AreNotEqual(fromUIGridColumnInfo.OrdinalPosition, expectedToUIGridColumnInfo.OrdinalPosition);
            Assert.AreNotEqual(ChangeType.Update, ((IMergableBo) expectedToUIGridColumnInfo).PendingChangeType);
            Assert.AreNotEqual(ChangeType.Delete, ((IMergableBo) expectedToUIGridColumnInfo2).PendingChangeType);
            //---------------Execute Test ----------------------
            uiGridColumnInfoMerger.MergeBOFrom(fromUIGridInfo, toUIGridInfo);
            //---------------Test Result -----------------------

            Assert.IsNotNull(toUIGridInfo);
            Assert.AreEqual(2, toUIGridInfo.UIColumns.Count);
            var toUIGridColumnInfo = toUIGridInfo.UIColumns.First();
            Assert.AreSame(toUIGridColumnInfo, expectedToUIGridColumnInfo);

            var toUIGridColumnInfo2 = toUIGridInfo.UIColumns.Last();
            Assert.AreSame(toUIGridColumnInfo2, expectedToUIGridColumnInfo2);
            Assert.AreEqual(ChangeType.Delete, ((IMergableBo) toUIGridColumnInfo2).PendingChangeType);
            Assert.AreEqual(ChangeType.None, ((IMergableBo) toUIGridColumnInfo).PendingChangeType);
        }

        [Test]
        public void Test_MergeUIGridInfo_WhenMergeToNotNull_ShouldUpdateUIGridInfo()
        {
            //---------------Set up test pack-------------------
            IMergeBO<UIGridInfo> mergeBO = MergeableBORegistry.Instance.Resolve<UIGridInfo>();
            var boTestFactory = TestUtilsUIGridInfo.GetFactory();
            var fromUIGridInfo = TestabilityExtensions.WithValueFor<UIGridInfo, string>(boTestFactory
                                                      .WithOutSingleRelationships(), frm => frm.SortColumn)
                .CreateValidBusinessObject();
            var toUIGrid = new UIGridInfo();
            //---------------Assert Precondition----------------
            Assert.AreNotEqual(fromUIGridInfo.SortColumn, toUIGrid.SortColumn);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromUIGridInfo, toUIGrid);
            //---------------Test Result -----------------------
            Assert.AreEqual(fromUIGridInfo.SortColumn, toUIGrid.SortColumn);
        }


        [Test]
        public void Test_MergeUIGridInfo_WhenAddGridFilter_ShouldCloneGridFilterAndAddToGrid()
        {
            //---------------Set up test pack-------------------
            IMergeBO<UIGridInfo> mergeBO = MergeableBORegistry.Instance.Resolve<UIGridInfo>();
            var fromUIGridInfo = TestUtilsUIGridInfo.CreateUnsavedValidUIGridInfo_WNoUIView();
            var fromGridFilter = new UIGridFilter
                    {
                        Columns = RandomValueGen.GetRandomInt()
                    };
            fromUIGridInfo.UIGridFilter = fromGridFilter;
            var toGrid = new UIGridInfo();
            //---------------Assert Precondition----------------
            Assert.IsNull(toGrid.UIGridFilter);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromUIGridInfo, toGrid);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toGrid.UIGridFilter);
            Assert.AreEqual(fromGridFilter.Columns, toGrid.UIGridFilter.Columns);
            Assert.AreEqual(fromGridFilter.FilterMode, toGrid.UIGridFilter.FilterMode);
            Assert.AreNotSame(fromGridFilter, toGrid.UIGridFilter);
        }
        [Test]
        public void Test_MergeUIGridInfo_WhenUpdateGridFilter_ShouldCloneGridFilterAndAddToProp()
        {
            //---------------Set up test pack-------------------
            IMergeBO<UIGridInfo> mergeBO = MergeableBORegistry.Instance.Resolve<UIGridInfo>();
            var fromUIGridInfo = TestUtilsUIGridInfo.CreateUnsavedValidUIGridInfo_WNoUIView();
            var filterFactory = TestUtilsUIGridFilter.GetFactory();
            var fromGridFilter = new UIGridFilter
            {
                Columns = RandomValueGen.GetRandomInt(),
                FilterMode = filterFactory.GetValidPropValue(filter => filter.FilterMode)
            };
            fromUIGridInfo.UIGridFilter = fromGridFilter;
            var expectedToGridFilter = new UIGridFilter();
            expectedToGridFilter.FilterMode = RandomValueGen.GetRandomEnum(fromGridFilter.FilterMode);
            var toGrid = new UIGridInfo { UIGridFilter = expectedToGridFilter };

            //---------------Assert Precondition----------------
            Assert.IsNotNull(toGrid.UIGridFilter);
            Assert.AreNotEqual(fromGridFilter.Columns, toGrid.UIGridFilter.Columns);
            Assert.AreNotEqual(fromGridFilter.FilterMode, toGrid.UIGridFilter.FilterMode);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromUIGridInfo, toGrid);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toGrid.UIGridFilter);
            Assert.AreEqual(fromGridFilter.Columns, toGrid.UIGridFilter.Columns);
            Assert.AreEqual(fromGridFilter.FilterMode, toGrid.UIGridFilter.FilterMode);
            Assert.AreSame(expectedToGridFilter, toGrid.UIGridFilter);
            Assert.AreNotSame(fromGridFilter, toGrid.UIGridFilter);
        }

        [Test]
        public void Test_MergeUIGridInfo_WhenDeleteGridFilter_ShouldMarkPendingChangesDelete()
        {
            //---------------Set up test pack-------------------
            IMergeBO<UIGridInfo> mergeBO = MergeableBORegistry.Instance.Resolve<UIGridInfo>();
            var fromGrid = TestUtilsUIGridInfo.CreateUnsavedValidUIGridInfo_WNoUIView();
            var toGrid = new UIGridInfo();
            var toGridFilter = new UIGridFilter
                                     {
                                         Columns = RandomValueGen.GetRandomInt()
                                     };
            toGrid.UIGridFilter = toGridFilter;
            //---------------Assert Precondition----------------
            Assert.IsNotNull(toGrid.UIGridFilter);
            Assert.IsNull(fromGrid.UIGridFilter);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromGrid, toGrid);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toGrid.UIGridFilter);
            Assert.AreEqual(ChangeType.Delete, ((IMergableBo)toGrid.UIGridFilter).PendingChangeType);
        }

        private static UIGridColumnInfo AddCopiedUIGridColumnInfo(UIGridInfo toUIGridInfo, UIGridColumnInfo fromUIGridColumnInfo)
        {
            var expectedToUIGridColumnInfo = new UIGridColumnInfo { PropertyName = fromUIGridColumnInfo.PropertyName };
            expectedToUIGridColumnInfo.OrdinalPosition = GetFactory().GetValidPropValue(gridColumn => gridColumn.OrdinalPosition);
            toUIGridInfo.UIColumns.Add(expectedToUIGridColumnInfo);
            return expectedToUIGridColumnInfo;
        }
        private static UIGridColumnInfo CreateUIGridColumnInfo(UIGridInfo uiGridInfo)
        {
            var uiGridColumnInfo = uiGridInfo.UIColumns.CreateBusinessObject();
            uiGridColumnInfo.OrdinalPosition = GetFactory().GetValidPropValue(gridColumn => gridColumn.OrdinalPosition);
            uiGridColumnInfo.PropertyName = GetFactory().GetValidPropValue(gridColumn => gridColumn.PropertyName);
            return uiGridColumnInfo;
        }



        [Test]
        public void Test_MatchUIGridFilterProp_WhenPropNameSame_ShouldRetTrue()
        {
            //---------------Set up test pack-------------------
            MergeBO<UIGridColumnInfo> mergeBO = new MergeUIGridColumnInfo();
            var gridColumnInfo = new UIGridColumnInfo
            {
                PropertyName = TestUtilsShared.GetRandomString()
            };
            var gridColumnInfo2 = new UIGridColumnInfo
            {
                PropertyName = gridColumnInfo.PropertyName
            };
            //---------------Assert Precondition----------------
            Assert.AreEqual(gridColumnInfo.PropertyName, gridColumnInfo2.PropertyName);
            //---------------Execute Test ----------------------
            bool matchBO = mergeBO.MatchBusinessObject(gridColumnInfo).Invoke(gridColumnInfo2);
            //---------------Test Result -----------------------
            Assert.IsTrue(matchBO);
        }

        [Test]
        public void Test_MatchUIGridFilterProp_WhenPropNameDiff_ShouldRetFalse()
        {
            //---------------Set up test pack-------------------
            MergeBO<UIGridColumnInfo> mergeBO = new MergeUIGridColumnInfo();
            var gridColumnInfo = new UIGridColumnInfo
            {
                PropertyName = TestUtilsShared.GetRandomString()
            };
            var gridColumnInfo2 = new UIGridColumnInfo
            {
                PropertyName = TestUtilsShared.GetRandomString()
            };
            //---------------Assert Precondition----------------
            Assert.AreNotEqual(gridColumnInfo.PropertyName, gridColumnInfo2.PropertyName);
            //---------------Execute Test ----------------------
            bool matchBO = mergeBO.MatchBusinessObject(gridColumnInfo).Invoke(gridColumnInfo2);
            //---------------Test Result -----------------------
            Assert.IsFalse(matchBO);
        }
    }
}